import sys
from PySide import QtGui, QtCore
import pickle

import time
import gen2_reader_edit
#from subprocess import *
import subprocess
from loadUiType import *

# The uic module contains a method called loadUiType (here I have used a custom user implementation of that module).
# We input the .ui file saved from the Qt Designer to this function. This method returns the "form class" and the "base
# class", which we need to derive from, and create a new window.
# The "holder" ui will act as a container for other ui windows.
# The "parameters" ui contains all the applicable variables that we can change through the spinboxes
holderBase, holderForm = loadUiType("../Views/Holder.ui")
parametersBase, parametersForm = loadUiType("../Views/Parameters.ui")

# The progress window may be used to display the progress of any time consuming task in the project.
# We are not using it right now but it may find some use later in the project.
class ProgressWindow(QtGui.QWidget):
    def __init__(self):
        super(ProgressWindow, self).__init__()
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle("oh yeah")
        self.progressbar = QtGui.QProgressBar(self)
        self.progressbar.setGeometry(30, 40, 200, 25)
        self.progressbar.setValue(80)
        # Need no Title bar
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        # Background coloring
        p = self.palette()
        p.setColor(self.backgroundRole(), QtCore.Qt.red)
        self.setPalette(p)

# Creating an object of the SplashScreen class at the start of the project will show a splash screen.
# The splash screen image is in the resources folder.
# The screen will wait until the main window has appeared.
class SplashScreen(object):
    def __init__(self, ex):
        super(SplashScreen, self).__init__()
        # Splash screen
        pixmap = QtGui.QPixmap("../Resources/rfidlogo.png")
        pixmap = pixmap.scaled(500, 500)
        splash = QtGui.QSplashScreen(pixmap)
        splash.show()
        # Loading some items
        splash.showMessage("Loaded modules")
        # Simulate something that takes time
        time.sleep(1)
        appObject.processEvents()
        # Establishing connections
        splash.showMessage("Established connections")
        # Simulate something that takes time
        time.sleep(1)
        appObject.processEvents()
        #ex = Window()
        # Makes the splash screen wait until the widget mainWin is displayed before calling PySide.QtGui.QWidget.close()
        # on itself.
        splash.finish(ex)

# The Main GUI Window is the primary user interface for this application.
# It acts as a container of all the widgets in this application like the menus, toolbar, status bar, progress bar,
# title and most importantly, the designer UIs (basically the holder ui).
# User can modify the spin box values and can invoke the "modified" RFID reader scripts. This will in turn invoke
# a "subprocess" in which the selected values will be passed to the modified RFID reader scripts as command-line
# arguments.
class Window(QtGui.QMainWindow):

    def __init__(self):
        super(Window, self).__init__()

        self.MaxRecentFiles = 5
        self.recentFileActions = []

        self.setGeometry(400, 50, 500, 450)
        self.setWindowTitle("RFID Smartplex")

        self.widget = QtGui.QWidget()

        self.layoutMain = QtGui.QVBoxLayout()
        self.widget.setLayout(self.layoutMain)

        self.setCentralWidget(self.widget)

        self._holder = Holder(self)
        self._holder.setParameters()   # Put default parameters for the first time into the spin boxes.
        self.layoutMain.addWidget(self._holder)

        self.hbox = QtGui.QHBoxLayout()

        self.hbox.addStretch(1)

        self.btnRun = QtGui.QPushButton("Run", self)
        self.btnRun.resize(self.btnRun.sizeHint())
        self.btnRun.setStatusTip("Run with the selected parameters!")
        self.btnRun.clicked.connect(self.runActionFunc)
        self.hbox.addWidget(self.btnRun)

        self.btnDefault = QtGui.QPushButton("Default", self)
        self.btnDefault.resize(self.btnDefault.sizeHint())
        self.btnDefault.setStatusTip("Restore all parameters to default values")
        self.btnDefault.clicked.connect(self.restoreDefaultFunc)
        self.hbox.addWidget(self.btnDefault)

        self.btnExit = QtGui.QPushButton("Quit", self)
        self.btnExit.clicked.connect(QtCore.QCoreApplication.instance().quit)
        self.btnExit.resize(self.btnExit.sizeHint())
        self.btnExit.setStatusTip("Exit the application")
        self.hbox.addWidget(self.btnExit)

        self.layoutMain.addLayout(self.hbox)

        self.createStatusBar()
        self.createActions()
        self.createMenus()
        self.createToolbar()


    # This function creates a Status Bar in the main application form.
    def createStatusBar(self):
        # Status bar
        # The status bar is a widget that is used for displaying status information
        self.statusBar().showMessage('Ready', 5000)
        # Progress bar
        # The progress bar widget can also be added to the status bar
        # Create the progress bar
        self.progressBar = QtGui.QProgressBar()
        # Add the progress bar as a permanent widget to the status bar
        self.statusBar().addPermanentWidget(self.progressBar)
        # This is simply to show the bar
        self.progressBar.setGeometry(30, 40, 200, 25)
        self.progressBar.setValue(100)

    # The createActions method create abstract user interface actions that can be inserted into widgets. In this
    # application we bind these actions with 1. Toolbar and 2. Menu items
    # First an empty action is created by calling QtGui.QAction constructor. The arguments passed to the constructor are
    # 1. Name of the icon image to be used
    # 2. Text (The same text will be used for tooltips unless you specify a different text using PySide.QtGui.QAction.setToolTip())
    # If we exclude the QIcon, then the text will be visible and can be used to execute the action.
    # 3. The parent (in most cases, as here, the parent is the main window)
    # A PySide.QtGui.QAction may contain an icon, menu text, a shortcut, status text, “What’s This?” text, and a tooltip.
    # Most of these can be set in the constructor. They can also be set independently with PySide.QtGui.QAction.setIcon(),
    # PySide.QtGui.QAction.setText() , PySide.QtGui.QAction.setIconText() , PySide.QtGui.QAction.setShortcut(),
    # PySide.QtGui.QAction.setStatusTip() , PySide.QtGui.QAction.setWhatsThis() , and PySide.QtGui.QAction.setToolTip().
    # For menu items, it is possible to set an individual font with PySide.QtGui.QAction.setFont()
    # Actions are added to widgets using QWidget.addAction() or QGraphicsWidget.addAction().
    # *******************************
    # We also wish to open the log files that were used recently. For that we need to generate five empty action objects.
    # This is done in a loop by repeatedly calling the append() method and providing a QtGui.QAction object to it.
    # We are also connecting it to the openRecentFileFunc slot. When triggered it will call the openRecentFileFunc.
    # After the empty actions have been created, we call the loadRecentFilesFromPickleFunc() to read back names of
    # recently used files from the pickle file provided for this purpose.
    def createActions(self):
        # Action items for the menu bar
        # A menu consists of a list of action items.
        # The PySide.QtGui.QAction class provides an abstract user interface action that can be inserted into widgets.
        # Create exitAction item
        self.exitAction = QtGui.QAction(QtGui.QIcon("../Resources/exit.png"), "&Exit", self)
        self.exitAction.setShortcut("Ctrl+X")
        self.exitAction.setStatusTip("Exit the application!")
        # When we select this particular action, a triggered signal is emitted. The signal is connected to the close()
        # method of the QtGui.QMainWindow widget. This terminates the application.
        self.exitAction.triggered.connect(self.exitActionFunc)

        # Create "Create New Log" Action item
        self.newLogAction = QtGui.QAction(QtGui.QIcon("../Resources/createNew.png"), "Create &New Log", self)
        self.newLogAction.setShortcut("Ctrl+N")
        self.newLogAction.setStatusTip("Create a New log file!")
        self.newLogAction.triggered.connect(self.newLogActionFunc)

        # Create "Select Log" Action item
        self.selectLogAction = QtGui.QAction(QtGui.QIcon("../Resources/openfile.png"), "&Open", self)
        self.selectLogAction.setShortcut("Ctrl+O")
        self.selectLogAction.setStatusTip("Select a log file!")
        self.selectLogAction.triggered.connect(self.selectLogActionFunc)

        # Create "Run" Action item
        self.runAction = QtGui.QAction(QtGui.QIcon("../Resources/run.png"), "&Run", self)
        self.runAction.setShortcut("Ctrl+R")
        self.runAction.setStatusTip("Run with selected parameters")
        self.runAction.triggered.connect(self.runActionFunc)

        # Create "About" Action item
        self.aboutAction = QtGui.QAction("&About", self)
        self.aboutAction.setShortcut("Ctrl+A")
        self.aboutAction.setStatusTip("About this project")
        self.aboutAction.triggered.connect(self.aboutActionFunc)

        # Generate empty actions to put the recent files actions into
        for i in range(self.MaxRecentFiles):
            self.recentFileActions.append(QtGui.QAction(self, visible=True, triggered=self.openRecentFileFunc))
        self.loadRecentFilesFromPickleFunc()

    # The createMenus method, creates menus parent window

    def createMenus(self):
        # Menu bar
        # Here the actual menu is made and populated with action items
        self.menuBar = self.menuBar()

        self.fileMenu = self.menuBar.addMenu("&File")
        self.fileMenu.addAction(self.newLogAction)  # Add the Select Log menu item
        self.fileMenu.addAction(self.selectLogAction)  # Add the Select Log menu item
        self.fileMenu.addSeparator()
        # Adding the recent file submenu under the file menu
        self.recentMenu = self.fileMenu.addMenu("Recent Files")
        # And populating it with the recent files extracted from pickle.txt
        for i in range(self.MaxRecentFiles):
            self.recentMenu.addAction(self.recentFileActions[i])
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAction)  # Add the exit menu item

        self.fileMenu = self.menuBar.addMenu("&Run")
        self.fileMenu.addAction(self.runAction)  # Add the run menu item

        self.fileMenu = self.menuBar.addMenu("&Help")
        self.fileMenu.addAction(self.aboutAction)

    # The createToolbar method, creates the toolbar on the parent window
    def createToolbar(self):
        # Toolbars
        # Menus group all commands that we can use in an application.
        # Toolbars provide a quick access to the most frequently used commands.
        # Just like menus, toolbars can also use action items
        self.toolbar = self.addToolBar('myQuickActions')
        self.toolbar.setIconSize(QtCore.QSize(40, 40))
        self.toolbar.addAction(self.newLogAction)
        self.toolbar.addAction(self.selectLogAction)
        self.toolbar.addAction(self.runAction)
        self.toolbar.addAction(self.exitAction)

    # Action objects invoke action functions.

    # The newLogActionFunc is invoked when you want to create a new log file.
    def newLogActionFunc(self):
        #print("Create a file Action")
        fName, filtr = QtGui.QFileDialog.getSaveFileName(self, "Create a new file!!", "D:\My_Documents")
        if fName:
            file = QtCore.QFile(fName)
            self.updateRecentFileListFunc(fName)
            if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
                QtGui.QMessageBox.warning(self, "Warning!!", "File not saved because %s:\n%s." % (fName, file.errorString()))
            return

    # The selectLogActionFunc opens up a window in which you can select a particular file. If the user selects that file
    # for opening, the function returns the data read from that file.
    def selectLogActionFunc(self):
        # We pop up the QtGui.QFileDialog. The first string in the getOpenFileName() method is the caption.
        # The second string specifies the dialog working directory. The method returns the selected file name and a
        # filter. We are only interested in the file name.
        # getOpenFileName(parent, [caption, [directory, [filter, [selectedFilter, [options]]]]])
        fName, filtr = QtGui.QFileDialog.getOpenFileName(self, "Open a file!!", "D:\My_Documents")
        # If the file name exists, it means that the user selected a file. Otherwise he may have selected cancel.
        if fName:
            self.updateRecentFileListFunc(fName)
            file = open(fName, 'r')
            with file:
                data = file.read()
                # self.textEdit.setText(data)
                return data

    # The openRecentFileFunc is used, if the user selets to open a file which is already in the recent files history.
    # It is referred to in the createActions method.
    def openRecentFileFunc(self):
        sender = self.sender()
        fName = sender.text()
        file = QtCore.QFile(fName)
        if not file.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text):
            QtGui.QMessageBox.warning(self, "This is a warning!!", "cannot read file %s\n%s" % (fName, file.errorString()))
            return
        file = open(fName, 'r')
        self.updateRecentFileListFunc(sender.text())
        with file:
            data = file.read()
            self.textEdit.setText(data)

    # A pickle file is used to save the recent files buffer. When the project loads up and the user works with a log file
    # then that file name is placed in a list that uses MRU up strategy. When the application exits, the current list
    # is dumped to the pickle to be loaded next time the application starts.
    # The loadRecentFilesFromPickleFunc loads the recent files from a pickle function, into a list. Once loaded, the
    # names are used to create actions.
    # This function is referred to in the createActions() function.
    def loadRecentFilesFromPickleFunc(self):
        # pickle protocol not supported error
        self.recentFiles = ["electronics", "vb6", "avr", "java", "now python"]
        """
        # Extracting recent file names stored in pickle file
        with open("pickle.txt", "rb") as fileObject:
        #             print("Loading back objects dumped through pickling")
        #             print(pickle.load(fileObject))
            self.recentFiles = pickle.load(fileObject)
            # self.recentFiles is now a "list". We will use this list and manipulate the filenames in it
            # In the end, when closing the program, we will save this list to pickle.txt
        #         print(self.recentFiles)
        """
        self.createActionsFromFileListFunc()

    # The updateRecentFileListFunc updates the current recent file list using the MRU up strategy.
    def updateRecentFileListFunc(self, sentFilename):
        if sentFilename:
            if sentFilename in self.recentFiles:
                # get the index of the sentFilename.
                self.recentFiles.index(sentFilename)
                # then remove the item from the list. Remember removing an item from the middle of the list, renumbers it :)
                self.recentFiles.remove(sentFilename)
                # then place the removed item name in the top of the list
                self.recentFiles.insert(0, sentFilename)
                # at this point the list should be in the order such that the most recent file is at top.
                self.createActionsFromFileListFunc()
            else:
                self.recentFiles.pop()
                # then insert the new item in the first place
                self.recentFiles.insert(0, sentFilename)
                # at this point the list should be in the order such that the most recent file is at top.
                self.createActionsFromFileListFunc()

    # The createActionsFromFileListFunc creates actions from the file names list.
    def createActionsFromFileListFunc(self):
        # Applying the file names in "recentFiles" list to actions
        i = -1
        for (actions) in self.recentFiles:
            i = i + 1
            self.recentFileActions[i].setText(actions)
#             print(self.recentFileActions[i].text())

    # The saveRecentFileListToPickleFunc dumps the updated recent file list to a pickle file.
    def saveRecentFileListToPickleFunc(self):
        # pickle protocol not supported
        pass
        """
        # Dumping objects through pickling
        with open("pickle.txt", "wb") as fileObject:
            pickle.dump(self.recentFiles, fileObject)
        """

    # The runActionFunc is executed when the user either presses the Run icon in the toolbar, or selects the Run command
    # in the Run menu, or presses the Run push button in the bottom of the application, or presses Ctrl+R
    def runActionFunc(self):
        subprocess.call(["python", "gen2_reader_edit.py"])
        #subprocess.check_call(["python", "gen2_reader_edit.py"])
        parameterValuesList = self._holder.getParameters()
        for (value) in parameterValuesList:
            print(value)

    # The restoreDefaultFun is executed if the user presses the Default push button in the GUI. The program first asks
    # for confirmation from the user and then restores the known working values into the GUI parameters.
    def restoreDefaultFunc(self):
        msgBoxReply = QtGui.QMessageBox.information(self, "Msg", "Are you sure", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
        if msgBoxReply == QtGui.QMessageBox.Yes:
            self._holder.setParameters()
        else:
            print("You press no")

    # The aboutActionFunc is executed when the user either selects the About menu item under the Help menu, or alternately, presses Ctrl+A
    def aboutActionFunc(self):
        QtGui.QMessageBox.about(self, "RFID Smartplex Begins", "Project under <br/><br/><b>Mr. Grzegorz Smietanka</b> and <br/><b>Mr Sebastian Brato</b>")

    # The exitActionFunc is executed at the time when the application exits execution.
    def exitActionFunc(self):
        # Before terminating the application, we wish to save the recent file list into the pickle.txt
        self.saveRecentFileListToPickleFunc()
        self.close()

# The Parameters class creates an object that embeds into the application. It holds all the GUI elements (spinboxes)
# that hold the values that would be sent to the reader script through command-line arguments.
class Parameters(parametersBase, parametersForm):
    def __init__(self, parent=None):
        super(parametersBase, self).__init__(parent)
        self.setupUi(self)
        # Signal-Slot mechanism to connect the uiPar3 valueChanged signal to the setGainOmega slot
        QtCore.QObject.connect(self.uiPar3, QtCore.SIGNAL("valueChanged(double)"), self.setGainOmega)

    def getParameters(self):
        parameterValuesList = [self.uiPar1.value(), self.uiPar2.value(), self.uiPar3.value(), self.uiPar4.value(),
                               self.uiPar5.value(), self.uiPar6.value(), self.uiPar7.value(), self.uiPar8.value()]
        return parameterValuesList

    def setParameters(self):
        print("I'm here!")
        self.uiPar1.setValue(5.00)      # Omega
        self.uiPar2.setValue(00.25)     # Mu
        self.uiPar3.setValue(00.25)     # Gain Mu
        val = 00.25 * self.uiPar3.value() * self.uiPar3.value()     # Gain Omega
        self.uiPar4.setValue(val)
        self.uiPar5.setValue(00.05)     # Omega Relative Limit
        self.uiPar6.setValue(5000.00)   # Amplitude
        self.uiPar7.setValue(90.00)     # Carrier Frequency (MHz)
        self.uiPar8.setValue(50.00)     # Number of Cycles

    def setGainOmega(self):
        val = 00.25 * self.uiPar3.value() * self.uiPar3.value()     # Gain Omega
        self.uiPar4.setValue(val)

# The Holder class object is used to hold all the form class objects generated by their respective uis.
# Currently we only have one ui for it hold (the Parameters.ui) but it can be extended to hold other uis in the future.
class Holder(holderBase, holderForm):
    def __init__(self, parent=None):
        super(holderBase, self).__init__(parent)
        self.setupUi(self)

        self._parameters = Parameters(self)

        # We want to dock the editors into the vertical layout element (layoutParam) in the UI
        self.vbox.addWidget(self._parameters)

    # This is just a wrapper function for the Parameters.getParameters() It is here to avoid using the
    # protected members of the Parameters.getParameters() directly.
    def getParameters(self):
        parameterValuesList = self._parameters.getParameters()
        return parameterValuesList

    # This is also a wrapper function to avoid direct use of the protected members of the Parameters class
    def setParameters(self):
        self._parameters.setParameters()

# The sequence of statements under the main keyword are the tasks to be performed in order for the application to do
# its desired task
if __name__ == "__main__":
    appObject = QtGui.QApplication(sys.argv)
    ex = Window()
    splash = SplashScreen(ex)
    time.sleep(1)
    #ex2 = ProgressWindow()
    ex.show()
    appObject.processEvents()
    time.sleep(1)
    #ex2.show()
    appObject.processEvents()
    time.sleep(1)
    #ex2.close()
    sys.exit(appObject.exec_())




#
##!/usr/bin/env python
#import sys
#import matplotlib
#matplotlib.use('Qt4Agg')
#matplotlib.rcParams['backend.qt4']='PySide'
#import pylab
#
#from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
#from matplotlib.figure import Figure
#
#from PySide import QtCore, QtGui
#from numpy import linspace
#
#class MatplotlibWidget(FigureCanvas):
#    def __init__(self, parent=None,xlabel='x',ylabel='y',title='Title', hold=False, yscale='linear'):
#        super(MatplotlibWidget, self).__init__(Figure())
#
#        self.setParent(parent)
#        self.figure = Figure()
#        self.canvas = FigureCanvas(self.figure)
#        self.axes = self.figure.add_subplot(111)
#
#        self.axes.set_xlabel(xlabel)
#        self.axes.set_ylabel(ylabel)
#        self.axes.set_title(title)
#
#    def  setupPlot(self):
#        # create a matplotlib widget
#        self.DataPlot = MatplotlibWidget()
#        # create a layout inside the blank widget and add the matplotlib widget
#        layout = QtGui.QVBoxLayout(self.ui.widget_PlotArea)
#        layout.addWidget(self.DataPlot,1)
#
#    def plotDataPoints(self,x,y):
#        self.DataPlot.axes.clear()
#        self.DataPlot.axes.plot(x,y,'bo-')
#        self.DataPlot.draw()
#
#class ApplicationWindow(QtGui.QMainWindow):
#        def __init__(self):
#            super(ApplicationWindow, self).__init__()   #QMainWindow.__init__(self)
#            self.mplwidget = MatplotlibWidget(self, title='Example', xlabel='Linear scale',
#                                              ylabel='Log scale', hold=True, yscale='log')
#            self.mplwidget.setFocus()
#            self.setCentralWidget(self.mplwidget)
#            self.plot(self.mplwidget.axes)
#
#        def plot(self, axes):
#            x = linspace(-10, 10)
#            axes.plot(x, x**2)
#            axes.plot(x, x**3)
#
#
#
#if __name__ == '__main__':
#    app = QtGui.QApplication(sys.argv)
#
#    ## generate the plot
#    #fig = Figure(figsize=(600,600), dpi=72, facecolor=(1,1,1), edgecolor=(0,0,0))
#    #ax = fig.add_subplot(111)
#    #ax.plot([0,1])
#    ## generate the canvas to display the plot
#    #canvas = FigureCanvas(fig)
#    #
#    #win = QtGui.QMainWindow()
#    ## add the plot canvas to a window
#    #win.setCentralWidget(canvas)
#
#    win = ApplicationWindow()
#    win.show()
#
#    sys.exit(app.exec_())